// pages/shopping/goods-list/index.js

import { getCategoryList, queryPageGoodsList } from '@/api/goods.js'
import { getTotalPage, msg, navTo } from '@/utils/util'

Component({

    options: {
        addGlobalClass: true
    },

    properties: {
        stickyTop: Number,
        cartList: { // 购物车数据
            type: Array,
            value: []
        },
        totalNum: Number, // 总数量 
        totalAmount: Number, // 总金额
    },

    data: {
        categoryList: [], // 商品分类
        goodsList: [], // 商品列表
        activeCategoryId: -1, // 当前选中的分类id
        pageNum: 1, 
        pageSize: 100,
        totalPage: 1, // 总页码
        leftScrollHeight: 0, // 左侧分类滚动区域的总高度
        leftScrollItemHeight: 0 // 分类项的高度
    },

    // 组件生命周期函数
    lifetimes: {
        attached() {
            this.loadCategoryList()
        }
    },

    pageLifetimes: {
        async show() {
            this.setData({ pageNum: 1 })
            await this.loadGoodsList()
            // 解决：当其他页面后退回来时，重新监听购物车数据，把它数量显示到商品列表中
            this.setData({cartList: this.properties.cartList})
        }
    },

    observers: {
        // 监听购物车的数据：更新商品列表数据、统计购买总数和总金额 
        cartList(cartList) {
            // 统计购买总数
            const totalNum = cartList.reduce((prev, curr) => {
                return prev + curr.buyNum
            }, 0)
            // 统计购买总金额 
            const totalAmount = cartList.reduce((prev, curr) => {
                return prev + curr.salePrice * curr.buyNum
            }, 0)
            
            // 更新商品列表数据
            const { goodsList } = this.data
            goodsList.forEach(goods => {
                // goods.buyNum = cartList.find(cart => cart._id == goods._id)?.buyNum || 0
                goods.buyNum = cartList.reduce((prev, curr) => {
                    return prev + (curr._id == goods._id ? curr.buyNum: 0)
                }, 0)
            })
            this.setData({ goodsList, totalNum, totalAmount: Number(totalAmount.toFixed(2)) })
            // console.log('监听器', totalNum, totalAmount, cartList, goodsList)
        },

        // 监听高亮显示分类时: 如果高亮的分类被隐藏则滚动滚动条,显示高亮的分类
        activeCategoryId(activeCategoryId) {
            const {leftScrollHeight, leftScrollItemHeight, categoryList} = this.data
            // 获取当前高亮分类所在的分类数据中的下标
            const index = categoryList.findIndex(item => item.categoryId == activeCategoryId)
            // console.log('index', index)
            // 计算目标分类距离 <scroll-view> 顶部的距离
            const offsetTop = index * leftScrollItemHeight
            // 120 - 520/2 = 120-260 = -140
            const leftScrollTop = offsetTop - leftScrollHeight / 2
            // console.log('leftScrollTop', leftScrollTop)
            this.setData({leftScrollTop})
        },

    },

    methods: {
        // str编码后返回
        encode(str) {
            return encodeURIComponent(str).replaceAll('%', '')
        },

        async loadCategoryList() {
            let { list: categoryList } = await getCategoryList()
            let activeCategoryId = -1
            if (categoryList && categoryList.length > 0) {
                // 将分类格式化：将分类名称进行编码后变成唯一分类id
                categoryList = categoryList.map(item => ({
                    categoryId: this.encode(item._id), categoryName: item._id
                }) )
                // 默认选中第1个
                activeCategoryId = categoryList[0].categoryId
            }
            // console.log('loadCategoryList', categoryList)
            this.setData({ categoryList, activeCategoryId }, this.getLeftScrollHeight)
        },

        // 点击分类
        handleCategory(e) {
            const { item } = e.currentTarget.dataset
            this.setData({ activeCategoryId: item.categoryId })

            // 点击分类时,将页面滚动到对应此分类的商品处
            this.tapCategoryScrollGoodsList(item)
        },

        // 查询商品列表
        async loadGoodsList() {
            let {pageNum, pageSize, totalPage} = this.data

            // 本次查询页码不能大于总页码，如果大于则不查询
            if (pageNum != 1 && pageNum > totalPage) {
                return
            }

            let { total, goodsList } = await queryPageGoodsList(pageNum, pageSize)

            // 计算总页码
            totalPage = getTotalPage(total, pageSize)

            // 添加一个分类id属性，并且将当前数据追加到原来的商品列表后面
            if (goodsList && goodsList.length > 0) {
                // 添加一个分类 categoryId属性
               goodsList = goodsList.map(item => ({...item, categoryId: this.encode(item.category)}) )
                // 如果查询的页码>1 , 当前数据追加到原来的商品列表后面  
                if (pageNum > 1) goodsList = this.data.goodsList.concat(goodsList)
            }

            this.setData({ totalPage, goodsList })

            // console.log('total, goodsList ', total, goodsList, totalPage )
        },

        // 页面滚动到达底部后，父页面会调用此方法
        reachBottomLoad() {
            // console.log('reachBottomLoad')
            const {pageNum} = this.data 
            this.setData({ pageNum: pageNum + 1 })
            this.loadGoodsList()
        },


        // 点击+添加到购物车
        handleItemAdd(e) {
            // 1.1为了解决点击+号,每次只加1, 组件中添加 data-buy-num="{{1}}"
            let { goods, buyNum } = e.currentTarget.dataset
            // console.log('handleItemAdd', goods, buyNum)

            const {_id, specs, specsId} = goods
            // 购物数量默认是1
            // const buyNum = goods.buyNum || 1
            // 1.2为了解决点击+号,每次只加1, 组件中添加 data-buy-num="{{1}}"
            buyNum = buyNum || goods.buyNum || 1

            // 购物车数据
            const { cartList = [] } = this.properties

            // 从购物车数据中获取本次添加的商品
            const target = cartList.find(item => item._id == _id && (item.specsId ? item.specsId == specs._id: true) )
            if (target) {
                // 购物车已存在此商品，则累加本次的数量
                target.buyNum = target.buyNum + buyNum 
            } else {
                // 不存在购物车：则购买数量1，加入到购物车
                const salePrice = goods.discountPrice || goods.price
                cartList.push({...goods, buyNum, salePrice})
            }
            // console.log('cartList', cartList)

            // 触发父组件的事件，传递购物车数据
            this.triggerEvent('updateCartList', { cartList } )

            // 开始动画：
            this.triggerEvent('startAnimation', e)
        },

        // 点击-减号
        handleItemSub(e) {
            const { goods } = e.currentTarget.dataset
            console.log('handleItemSub', goods)

            const cartList = this.data.cartList || []

            // 从购物车数据中查找被点击的那个商品
            const targetIndex = cartList.findIndex(item => item._id === goods._id)
            // 购物车没有此商品，则直接结束
            if (targetIndex < 0) return

            const target = cartList[targetIndex]
            if (target.buyNum > 1) {
                // 数量大于1，则数量减1
                target.buyNum--
            } else {
                // 数量小于或等于1，则从购物车移除
                cartList.splice(targetIndex, 1)
            }

            // 更新购物车的数据
            this.triggerEvent('updateCartList', { cartList })

        },

        // 点击数字
        async handleItemNum(e) {
            const { goods } = e.currentTarget.dataset
            console.log('handleItemNum', goods)

            const {cancel, content} = await wx.showModal({
                title: '请输入商品数量',
                editable: true, // 显示输入框
                placeholderText: '请输入0到10000之间的数字',
                content: `${goods.buyNum || ''}` // 只能是字符串，不能是数字，不然报错
            })
            if (cancel) return 
            // console.log('content', content)

            // 点击确定按钮后往下执行：
            const updateNum = parseInt(content)
            // console.log('updateNum', updateNum, isNaN(updateNum))
            if (isNaN(updateNum) || updateNum < 0 || updateNum > 10000) {
                return msg('请输入有效数字', {icon: 'error'})
            }

            // 把新的数量更新到购物车中
            const { cartList = [] } = this.properties
            const targetIndex = cartList.findIndex(item => item._id === goods._id)
            if (targetIndex < 0) return 

            const target = cartList[targetIndex]
            if (updateNum > 0) {
                // 输入的值大于0，则直接将此数量作为最新数量
                target.buyNum = updateNum
            } else {
                // 小于等于0，从购物车移除
                cartList.splice(targetIndex, 1)
            }

            // console.log('target', target, cartList)

            this.triggerEvent('updateCartList', { cartList })
        },

        // 跳转详情页
        toGoodsDetail(e) {
            const { item } = e.currentTarget.dataset
            console.log('toGoodsDetail', item)
            navTo('/pages/goods-detail/goods-detail?goods='+ JSON.stringify(item), {
                events: {
                    addToCart: (goods) => {
                        // e.currentTarget.dataset.goods
                        console.log('addToCart', goods)
                        this.handleItemAdd({currentTarget: { dataset: { goods: goods} } })
                    }
                }
            })
        },

        // 点击分类时,将页面滚动到对应此分类的商品处
        tapCategoryScrollGoodsList(item) {
            // 用于控制当点击分类后会滚动页面,滚动页面时会调用页面事件函数
            // 通过此属性来控制当点击分类后,不进行调用页面事件函数处理逻辑不执行pageScrollChangeCategory
            this.isTapCategory = true

            // console.log('tapCategoryScrollGoodsList', `.right${item.categoryId}`)
            wx.pageScrollTo({
                // 要使用 跨自定义组件的后代选择器, >>> 左右两边空格, #goods-list-id是在shopping.wxml中的节点id属性值, .rightxxxx是当前子组件的class属性值
                selector: `#goods-list-id >>> .right${item.categoryId}`,
                offsetTop: -this.properties.stickyTop - 15,
                complete: () => {
                    // 滚动完成
                    setTimeout(() => {
                        this.isTapCategory = false
                    }, 500);
                }
            })
        },

        // shopping.js中当页面滚动时触发了此方法, 来实现高亮显示分类名称
        pageScrollChangeCategory(e) {
            // 如果点击的是分类引发的页面滚动,则后面逻辑不执行
            if (this.isTapCategory) return

            // console.log('pageScrollChangeCategory', e)

            let { activeCategoryId, stickyTop } = this.data
            // 获取每个商品到顶部的距离
            // 特别注意: 子组件中通过 this.createSelectorQuery获取,
            // 不是通过  wx.createSelectorQuery
            this.createSelectorQuery().selectAll('.goods-item').boundingClientRect(res => {
                // console.log("res", res)
                res.forEach(rect => {
                    // 每个商品距离顶部的高度top - 上方吸顶的高度 <= 0 则高亮当前商品的分类名称
                    if (rect.top - stickyTop <= 0) {
                        // 在 index.wxml中添加一个 data-category-id="{{item.categoryId}}"
                        activeCategoryId = rect.dataset.categoryId
                    }
                })
                // 更新高亮显示的分类id
                this.setData({ activeCategoryId })
            }).exec()
        },

        // 当分类数据渲染完成后, 获取左侧整个分类滚动区域的高度和分类项的高度
        getLeftScrollHeight() {
            // console.log('getLeftScrollHeight')
            const query = this.createSelectorQuery()
            // 获取左侧整个分类滚动区域的高度
            query.select('.category-scroll').boundingClientRect(rect => {
                this.setData({ leftScrollHeight: Math.round(rect.height) })
            }).exec()

            // 获取左侧分类项的高度
            query.select('.category-item').boundingClientRect(rect => {
                this.setData({ leftScrollItemHeight: Math.round(rect.height) })
            }).exec()

        }

    }

})